fix(request): linear SSE buffering with pre-append size check - #418
Conversation
Addresses REQ-HIGH-03 deep-audit finding. Previous: fullText += decoder.decode(...) caused O(n^2) string concatenation in convertSseToJson; MAX_SSE_SIZE check ran AFTER append so memory briefly held chunk + 10MB before throwing. Fix: accumulate chunks in string[] array; track running size; check size BEFORE append; final join() once at end. Linear time, bounded memory, size-check enforced pre-allocation. Test asserts pre-append throw when next chunk would exceed cap.
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 56 minutes and 28 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Responds to PR #418 review feedback. The pre-append SSE size guard used decoded.length, which counts UTF-16 code units rather than bytes. Multi-byte UTF-8 chunks (emoji, many CJK chars) could therefore exceed MAX_SSE_SIZE without tripping the guard at the right point. Use Buffer.byteLength(decoded, 'utf8') for both the pre-append check and the running total, and add a regression test covering a multi-byte payload.
Summary
Addresses deep-audit finding
REQ-HIGH-03:convertSseToJsoninlib/request/response-handler.tsbuffered the entire SSE stream via repeatedfullText += decoder.decode(...). That is O(n) per append on V8, producing O(n^2) total work for large streams, and theMAX_SSE_SIZE(10 MB) cap was enforced AFTER the append, so peak memory briefly heldchunk + 10 MBbefore throwing.Fix
string[]andjoin('')once at the end (linear total work).totalSizecounter.totalSize + decoded.length > MAX_SSE_SIZEBEFORE appending each chunk, so the cap is enforced pre-allocation and peak memory is bounded to the cap rather thancap + chunk.Tests
New dedicated regression file
test/response-handler-sse-buffer.test.ts(3 tests), isolated from the existing 860-lineresponse-handler.test.tsto avoid whole-file reformatting noise in the diff:Verification
npm test -- response-handler— 56 passed (was 53; +3 regression tests)npm run typecheck— cleannpm run lint— cleanConstraints observed
as any,@ts-ignore, or@ts-expect-error.lib/request/response-handler.tsand a new co-locatedresponse-handler-scoped test file.note: greptile review for oc-chatgpt-multi-auth. cite files like
lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.Greptile Summary
the pr correctly replaces O(n²) string concatenation with an array-then-join pattern and enforces the 10 MB cap before each append. the follow-up commit (
afd1fff) also switched fromdecoded.length(utf-16 code units) toBuffer.byteLength(decoded, "utf8"), addressing the prior review comment — thoughvalue.byteLengthwould be simpler, avoids re-encoding, and is slightly tighter at multi-byte chunk boundaries.Confidence Score: 5/5
safe to merge; both remaining findings are P2 style suggestions with no correctness impact
the core fix is correct — linear accumulation, pre-append guard, and proper utf-8 byte counting all work. the
Buffer.byteLengthvsvalue.byteLengthdifference is a minor efficiency/elegance nit, not a bug; totals are equivalent over the full stream. four targeted regression tests cover all three original scenarios plus the utf-8 edge case. no security, data-loss, or concurrency issues.no files require special attention
Important Files Changed
Buffer.byteLength(decoded, "utf8")re-encodes needlessly —value.byteLengthis simpler and tighter at chunk boundariesbuildChunkedReaderis stale after the utf-8 fixFlowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[reader.read] --> B{done?} B -- yes --> G[chunks.join] B -- no --> C[decoder.decode value stream:true] C --> D[decodedBytes = Buffer.byteLength decoded utf8] D --> E{totalSize + decodedBytes > MAX_SSE_SIZE?} E -- yes --> F[throw + reader.cancel] E -- no --> H[chunks.push decoded\ntotalSize += decodedBytes] H --> A G --> I[parseSseStream fullText] I --> J{finalResponse?} J -- no --> K[return plain text Response] J -- yes --> L[return JSON Response]Prompt To Fix All With AI
Reviews (2): Last reviewed commit: "fix(request): count utf-8 bytes in SSE s..." | Re-trigger Greptile